home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / ghostscr / gsview07.zip / ps.c < prev    next >
C/C++ Source or Header  |  1993-04-23  |  45KB  |  1,379 lines

  1. /*
  2.  * ps.c -- Postscript scanning and copying routines.
  3.  * Copyright (C) 1992  Timothy O. Theisen
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *   Author: Tim Theisen           Systems Programmer
  20.  * Internet: tim@cs.wisc.edu       Department of Computer Sciences
  21.  *     UUCP: uwvax!tim             University of Wisconsin-Madison
  22.  *    Phone: (608)262-0438         1210 West Dayton Street
  23.  *      FAX: (608)262-9777         Madison, WI   53706
  24.  *
  25.  * This file has been modified by Russell Lang (rjl@monu1.cc.monash.edu.au)
  26.  * 1993-04-23
  27.  * - Header file includes changed for MS-Windows.
  28.  * - MS-DOS carriage return handling added.
  29.  * - Ignore ^D as first character of file
  30.  * - Allow %%Pages: 0
  31.  */
  32.  
  33. #include <stdio.h>
  34. #ifdef __TURBOC__
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <ctype.h>
  38. #define strcasecmp(s,t) stricmp(s,t)
  39. extern void pserror(char *str);
  40. #else
  41. #ifndef SEEK_SET
  42. #define SEEK_SET 0
  43. #endif
  44. #ifndef BUFSIZ
  45. #define BUFSIZ 1024
  46. #endif
  47. #include <ctype.h>
  48. #include <X11/Xos.h>        /* #includes the appropriate <string.h> */
  49. #define pserror(str) fprintf(stderr,str)
  50. #endif
  51. #include "ps.h"
  52.  
  53. #ifdef BSD4_2
  54. #define memset(a,b,c) bzero(a,c)
  55. #endif
  56.  
  57. /* length calculates string length at compile time */
  58. /* can only be used with character constants */
  59. #define length(a) (sizeof(a)-1)
  60. #define iscomment(a, b)    (strncmp(a, b, length(b)) == 0)
  61.  
  62.     /* list of standard paper sizes from Adobe's PPD. */
  63.  
  64. struct documentmedia papersizes[] = {
  65.     "Letter",         612,  792,
  66.     "LetterSmall",     612,  792,
  67.     "Tabloid",         792, 1224,
  68.     "Ledger",        1224,  792,
  69.     "Legal",         612, 1008,
  70.     "Statement",     396,  612,
  71.     "Executive",     540,  720,
  72.     "A3",         842, 1190,
  73.     "A4",         595,  842,
  74.     "A4Small",         595,  842,
  75.     "A5",         420,  595,
  76.     "B4",         729, 1032,
  77.     "B5",         516,  729,
  78.     "Folio",         612,  936,
  79.     "Quarto",         610,  780,
  80.     "10x14",         720, 1008,
  81.     NULL,           0,    0
  82. };
  83.  
  84.  
  85. static char *readline();
  86. static char *gettextline();
  87. static char *gettext();
  88. static int  blank();
  89.  
  90. /*
  91.  *    psscan -- scan the PostScript file for document structuring comments.
  92.  *
  93.  *    This scanner is designed to retrieve the information necessary for
  94.  *    the ghostview previewer.  It will scan files that conform to any
  95.  *    version (1.0, 2.0, 2.1, or 3.0) of the document structuring conventions.
  96.  *    It does not really care which version of comments the file contains.
  97.  *    (The comments are largely upward compatible.)  It will scan a number
  98.  *    of non-conforming documents.  (You could have part of the document
  99.  *    conform to V2.0 and the rest conform to V3.0.  It would be similar
  100.  *    to the DC-2 1/2+, it would look funny but it can still fly.)
  101.  *
  102.  *    This routine returns a pointer to the document structure.
  103.  *    The structure contains the information relevant to previewing.
  104.  *      These include EPSF flag (to tell if the file is a encapsulated figure),
  105.  *      Page Media (for the Page Size), Bounding Box (to minimize backing
  106.  *      pixmap size or determine window size for encapsulated PostScript), 
  107.  *      Orientation of Paper (for default transformation matrix), and
  108.  *      Page Order.  The title and CreationDate are also retrieved to
  109.  *      help identify the document.
  110.  *
  111.  *      The following comments are examined:
  112.  *
  113.  *      Header section: 
  114.  *      Must start with %!PS-Adobe-.  Version numbers ignored.
  115.  *
  116.  *      %!PS-Adobe-* [EPSF-*]
  117.  *      %%BoundingBox: <int> <int> <int> <int>|(atend)
  118.  *      %%CreationDate: <textline>
  119.  *      %%Orientation: Portrait|Landscape|(atend)
  120.  *      %%Pages: <uint> [<int>]|(atend)
  121.  *      %%PageOrder: Ascend|Descend|Special|(atend)
  122.  *      %%Title: <textline>
  123.  *      %%DocumentMedia: <text> <real> <real> <real> <text> <text>
  124.  *      %%DocumentPaperSizes: <text>
  125.  *      %%EndComments
  126.  *
  127.  *      Note: Either the 3.0 or 2.0 syntax for %%Pages is accepted.
  128.  *            Also either the 2.0 %%DocumentPaperSizes or the 3.0
  129.  *            %%DocumentMedia comments are accepted as well.
  130.  *
  131.  *      The header section ends either explicitly with %%EndComments or
  132.  *      implicitly with any line that does not begin with %X where X is
  133.  *      a not whitespace character.
  134.  *
  135.  *      If the file is encapsulated PostScript the optional Preview section
  136.  *      is next:
  137.  *
  138.  *      %%BeginPreview
  139.  *      %%EndPreview
  140.  *
  141.  *      This section explicitly begins and ends with the above comments.
  142.  *
  143.  *      Next the Defaults section for version 3 page defaults:
  144.  *
  145.  *      %%BeginDefaults
  146.  *      %%PageBoundingBox: <int> <int> <int> <int>
  147.  *      %%PageOrientation: Portrait|Landscape
  148.  *      %%PageMedia: <text>
  149.  *      %%EndDefaults
  150.  *
  151.  *      This section explicitly begins and ends with the above comments.
  152.  *
  153.  *      The prolog section either explicitly starts with %%BeginProlog or
  154.  *      implicitly with any nonblank line.
  155.  *
  156.  *      %%BeginProlog
  157.  *      %%EndProlog
  158.  *
  159.  *      The Prolog should end with %%EndProlog, however the proglog implicitly
  160.  *      ends when %%BeginSetup, %%Page, %%Trailer or %%EOF are encountered.
  161.  *
  162.  *      The Setup section is where the version 2 page defaults are found.
  163.  *      This section either explicitly begins with %%BeginSetup or implicitly
  164.  *      with any nonblank line after the Prolog.
  165.  *
  166.  *      %%BeginSetup
  167.  *      %%PageBoundingBox: <int> <int> <int> <int>
  168.  *      %%PageOrientation: Portrait|Landscape
  169.  *      %%PaperSize: <text>
  170.  *      %%EndSetup
  171.  *
  172.  *      The Setup should end with %%EndSetup, however the setup implicitly
  173.  *      ends when %%Page, %%Trailer or %%EOF are encountered.
  174.  *
  175.  *      Next each page starts explicitly with %%Page and ends implicitly with
  176.  *      %%Page or %%Trailer or %%EOF.  The following comments are recognized:
  177.  *
  178.  *      %%Page: <text> <uint>
  179.  *      %%PageBoundingBox: <int> <int> <int> <int>|(atend)
  180.  *      %%PageOrientation: Portrait|Landscape
  181.  *      %%PageMedia: <text>
  182.  *      %%PaperSize: <text>
  183.  *
  184.  *      The tralier section start explicitly with %%Trailer and end with %%EOF.
  185.  *      The following comment are examined with the proper (atend) notation
  186.  *      was used in the header:
  187.  *
  188.  *      %%Trailer
  189.  *      %%BoundingBox: <int> <int> <int> <int>|(atend)
  190.  *      %%Orientation: Portrait|Landscape|(atend)
  191.  *      %%Pages: <uint> [<int>]|(atend)
  192.  *      %%PageOrder: Ascend|Descend|Special|(atend)
  193.  *      %%EOF
  194.  *
  195.  *
  196.  *  + A DC-3 received severe damage to one of its wings.  The wing was a total
  197.  *    loss.  There was no replacement readily available, so the mechanic
  198.  *    installed a wing from a DC-2.
  199.  */
  200.  
  201. struct document *
  202. psscan(file)
  203.     FILE *file;
  204. {
  205.     struct document *doc;
  206.     int bb_set = NONE;
  207.     int pages_set = NONE;
  208.     int page_order_set = NONE;
  209.     int orientation_set = NONE;
  210.     int page_bb_set = NONE;
  211.     int page_media_set = NONE;
  212.     int preread;        /* flag which tells the readline isn't needed */
  213.     int i;
  214.     unsigned int maxpages = 0;
  215.     unsigned int nextpage = 1;    /* Next expected page */
  216.     unsigned int thispage;
  217.     int ignore = 0;        /* whether to ignore page ordinals */
  218.     char *label;
  219.     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
  220.     char text[PSLINELENGTH];    /* Temporary storage for text */
  221.     long position;        /* Position of the current line */
  222.     unsigned int line_len;     /* Length of the current line */
  223.     unsigned int section_len;    /* Place to accumulate the section length */
  224.     char *next_char;        /* 1st char after text returned by gettext() */
  225.     char *cp;
  226.     struct documentmedia *dmp;
  227.  
  228.     rewind(file);
  229.     if (fgetc(file) != '\004')
  230.         rewind(file);
  231.     if (readline(line, sizeof line, file, &position, &line_len) == NULL) {
  232.     pserror("Warning: empty file.\n");
  233.     return(NULL);
  234.     }
  235.  
  236.     /* Header comments */
  237.  
  238.     if (iscomment(line,"%!PS-Adobe-")) {
  239.     doc = (struct document *) malloc(sizeof(struct document));
  240.     if (doc == NULL) {
  241.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  242.         exit(-1);
  243.     }
  244.     memset(doc, 0, sizeof(struct document));
  245.     sscanf(line, "%*s %s", text);
  246.     doc->epsf = iscomment(text, "EPSF-");
  247.     doc->beginheader = position;
  248.     section_len = line_len;
  249.     } else {
  250.     return(NULL);
  251.     }
  252.  
  253.     preread = 0;
  254.     while (preread || readline(line, sizeof line, file, &position, &line_len)) {
  255.     if (!preread) section_len += line_len;
  256.     preread = 0;
  257.     if (iscomment(line, "%%EndComments") ||
  258.         line[0] != '%' ||
  259.         (!isprint(line[1]) || line[1] == ' ' ||
  260.          line[1] == '\t' || line[1] == '\n')) {
  261.         break;
  262.     } else if (!iscomment(line, "%%")) {
  263.         /* Do nothing */
  264.     } else if (doc->title == NULL && iscomment(line+2, "Title:")) {
  265.         doc->title = gettextline(line+length("%%Title:"));
  266.     } else if (doc->date == NULL && iscomment(line+2, "CreationDate:")) {
  267.         doc->date = gettextline(line+length("%%CreationDate:"));
  268.     } else if (bb_set == NONE && iscomment(line+2, "BoundingBox:")) {
  269.         sscanf(line+length("%%BoundingBox:"), "%s", text);
  270.         if (strcmp(text, "(atend)") == 0) {
  271.         bb_set = ATEND;
  272.         } else {
  273.         if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
  274.                &(doc->boundingbox[LLX]),
  275.                &(doc->boundingbox[LLY]),
  276.                &(doc->boundingbox[URX]),
  277.                &(doc->boundingbox[URY])) == 4)
  278.             bb_set = 1;
  279.         else {
  280.             float fllx, flly, furx, fury;
  281.             if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
  282.                    &fllx, &flly, &furx, &fury) == 4) {
  283.             bb_set = 1;
  284.             doc->boundingbox[LLX] = fllx;
  285.             doc->boundingbox[LLY] = flly;
  286.             doc->boundingbox[URX] = furx;
  287.             doc->boundingbox[URY] = fury;
  288.             if (fllx < doc->boundingbox[LLX])
  289.                 doc->boundingbox[LLX]--;
  290.             if (flly < doc->boundingbox[LLY])
  291.                 doc->boundingbox[LLY]--;
  292.             if (furx > doc->boundingbox[URX])
  293.                 doc->boundingbox[URX]++;
  294.             if (fury > doc->boundingbox[URY])
  295.                 doc->boundingbox[URY]++;
  296.             }
  297.         }
  298.         }
  299.     } else if (orientation_set == NONE &&
  300.            iscomment(line+2, "Orientation:")) {
  301.         sscanf(line+length("%%Orientation:"), "%s", text);
  302.         if (strcmp(text, "(atend)") == 0) {
  303.         orientation_set = ATEND;
  304.         } else if (strcmp(text, "Portrait") == 0) {
  305.         doc->orientation = PORTRAIT;
  306.         orientation_set = 1;
  307.         } else if (strcmp(text, "Landscape") == 0) {
  308.         doc->orientation = LANDSCAPE;
  309.         orientation_set = 1;
  310.         }
  311.     } else if (page_order_set == NONE && iscomment(line+2, "PageOrder:")) {
  312.         sscanf(line+length("%%PageOrder:"), "%s", text);
  313.         if (strcmp(text, "(atend)") == 0) {
  314.         page_order_set = ATEND;
  315.         } else if (strcmp(text, "Ascend") == 0) {
  316.         doc->pageorder = ASCEND;
  317.         page_order_set = 1;
  318.         } else if (strcmp(text, "Descend") == 0) {
  319.         doc->pageorder = DESCEND;
  320.         page_order_set = 1;
  321.         } else if (strcmp(text, "Special") == 0) {
  322.         doc->pageorder = SPECIAL;
  323.         page_order_set = 1;
  324.         }
  325.     } else if (pages_set == NONE && iscomment(line+2, "Pages:")) {
  326.         sscanf(line+length("%%Pages:"), "%s", text);
  327.         if (strcmp(text, "(atend)") == 0) {
  328.         pages_set = ATEND;
  329.         } else {
  330.         switch (sscanf(line+length("%%Pages:"), "%d %d",
  331.                    &maxpages, &i)) {
  332.             case 2:
  333.             if (page_order_set == NONE) {
  334.                 if (i == -1) {
  335.                 doc->pageorder = DESCEND;
  336.                 page_order_set = 1;
  337.                 } else if (i == 0) {
  338.                 doc->pageorder = SPECIAL;
  339.                 page_order_set = 1;
  340.                 } else if (i == 1) {
  341.                 doc->pageorder = ASCEND;
  342.                 page_order_set = 1;
  343.                 }
  344.             }
  345.             case 1:
  346.               if (maxpages != 0) { /* this line added by rjl */
  347.             doc->pages = (struct page *) calloc(maxpages,
  348.                             sizeof(struct page));
  349.             if (doc->pages == NULL) {
  350.                 pserror("Fatal Error: Dynamic memory exhausted.\n");
  351.                 exit(-1);
  352.             }
  353.               } /* this line added by rjl */
  354.         }
  355.         }
  356.     } else if (doc->nummedia == NONE &&
  357.            iscomment(line+2, "DocumentMedia:")) {
  358.         float w, h;
  359.         doc->media = (struct documentmedia *)
  360.              malloc(sizeof (struct documentmedia));
  361.         if (doc->media == NULL) {
  362.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  363.         exit(-1);
  364.         }
  365.         doc->media[0].name = gettext(line+length("%%DocumentMedia:"),
  366.                      &next_char);
  367.         if (doc->media[0].name != NULL) {
  368.         if (sscanf(next_char, "%f %f", &w, &h) == 2) {
  369.             doc->media[0].width = w + 0.5;
  370.             doc->media[0].height = h + 0.5;
  371.         }
  372.         if (doc->media[0].width != 0 && doc->media[0].height != 0)
  373.             doc->nummedia = 1;
  374.         else
  375.             free(doc->media[0].name);
  376.         }
  377.         preread=1;
  378.         while (readline(line, sizeof line, file, &position, &line_len) &&
  379.            iscomment(line, "%%+")) {
  380.         section_len += line_len;
  381.         doc->media = (struct documentmedia *)
  382.                  realloc(doc->media,
  383.                      (doc->nummedia+1)*
  384.                      sizeof (struct documentmedia));
  385.         if (doc->media == NULL) {
  386.             pserror("Fatal Error: Dynamic memory exhausted.\n");
  387.             exit(-1);
  388.         }
  389.         doc->media[doc->nummedia].name = gettext(line+length("%%+"),
  390.                              &next_char);
  391.         if (doc->media[doc->nummedia].name != NULL) {
  392.             if (sscanf(next_char, "%f %f", &w, &h) == 2) {
  393.             doc->media[doc->nummedia].width = w + 0.5;
  394.             doc->media[doc->nummedia].height = h + 0.5;
  395.             }
  396.             if (doc->media[doc->nummedia].width != 0 &&
  397.             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  398.             else
  399.             free(doc->media[doc->nummedia].name);
  400.         }
  401.         }
  402.         section_len += line_len;
  403.         if (doc->nummedia != 0) doc->default_page_media = doc->media;
  404.     } else if (doc->nummedia == NONE &&
  405.            iscomment(line+2, "DocumentPaperSizes:")) {
  406.  
  407.         doc->media = (struct documentmedia *)
  408.              malloc(sizeof (struct documentmedia));
  409.         if (doc->media == NULL) {
  410.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  411.         exit(-1);
  412.         }
  413.         doc->media[0].name = gettext(line+length("%%DocumentPaperSizes:"),
  414.                      &next_char);
  415.         if (doc->media[0].name != NULL) {
  416.         doc->media[0].width = 0;
  417.         doc->media[0].height = 0;
  418.         for (dmp=papersizes; dmp->name != NULL; dmp++) {
  419.             /* Note: Paper size comment uses down cased paper size
  420.              * name.  Case insensitive compares are only used for
  421.              * PaperSize comments.
  422.              */
  423.             if (strcasecmp(doc->media[0].name, dmp->name) == 0) {
  424.             free(doc->media[0].name);
  425.             doc->media[0].name =
  426.                 (char *)malloc(strlen(dmp->name)+1);
  427.             if (doc->media[0].name == NULL) {
  428.                 pserror("Fatal Error: Dynamic memory exhausted.\n");
  429.                 exit(-1);
  430.             }
  431.             strcpy(doc->media[0].name, dmp->name);
  432.             doc->media[0].width = dmp->width;
  433.             doc->media[0].height = dmp->height;
  434.             break;
  435.             }
  436.         }
  437.         if (doc->media[0].width != 0 && doc->media[0].height != 0)
  438.             doc->nummedia = 1;
  439.         else
  440.             free(doc->media[0].name);
  441.         }
  442.         while (cp = gettext(next_char, &next_char)) {
  443.         doc->media = (struct documentmedia *)
  444.                  realloc(doc->media,
  445.                      (doc->nummedia+1)*
  446.                      sizeof (struct documentmedia));
  447.         if (doc->media == NULL) {
  448.             pserror("Fatal Error: Dynamic memory exhausted.\n");
  449.             exit(-1);
  450.         }
  451.         doc->media[doc->nummedia].name = cp;
  452.         doc->media[doc->nummedia].width = 0;
  453.         doc->media[doc->nummedia].height = 0;
  454.         for (dmp=papersizes; dmp->name != NULL; dmp++) {
  455.             /* Note: Paper size comment uses down cased paper size
  456.              * name.  Case insensitive compares are only used for
  457.              * PaperSize comments.
  458.              */
  459.             if (strcasecmp(doc->media[doc->nummedia].name,
  460.                    dmp->name) == 0) {
  461.             free(doc->media[doc->nummedia].name);
  462.             doc->media[doc->nummedia].name =
  463.                 (char *)malloc(strlen(dmp->name)+1);
  464.             if (doc->media[doc->nummedia].name == NULL) {
  465.                 pserror("Fatal Error: Dynamic memory exhausted.\n");
  466.                 exit(-1);
  467.             }
  468.             strcpy(doc->media[doc->nummedia].name, dmp->name);
  469.             doc->media[doc->nummedia].name = dmp->name;
  470.             doc->media[doc->nummedia].width = dmp->width;
  471.             doc->media[doc->nummedia].height = dmp->height;
  472.             break;
  473.             }
  474.         }
  475.         if (doc->media[doc->nummedia].width != 0 &&
  476.             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  477.         else
  478.             free(doc->media[doc->nummedia].name);
  479.         }
  480.         preread=1;
  481.         while (readline(line, sizeof line, file, &position, &line_len) &&
  482.            iscomment(line, "%%+")) {
  483.         section_len += line_len;
  484.         next_char = line + length("%%+");
  485.         while (cp = gettext(next_char, &next_char)) {
  486.             doc->media = (struct documentmedia *)
  487.                  realloc(doc->media,
  488.                      (doc->nummedia+1)*
  489.                      sizeof (struct documentmedia));
  490.             if (doc->media == NULL) {
  491.             pserror("Fatal Error: Dynamic memory exhausted.\n");
  492.             exit(-1);
  493.             }
  494.             doc->media[doc->nummedia].name = cp;
  495.             doc->media[doc->nummedia].width = 0;
  496.             doc->media[doc->nummedia].height = 0;
  497.             for (dmp=papersizes; dmp->name != NULL; dmp++) {
  498.             /* Note: Paper size comment uses down cased paper size
  499.              * name.  Case insensitive compares are only used for
  500.              * PaperSize comments.
  501.              */
  502.             if (strcasecmp(doc->media[doc->nummedia].name,
  503.                    dmp->name) == 0) {
  504.                 doc->media[doc->nummedia].width = dmp->width;
  505.                 doc->media[doc->nummedia].height = dmp->height;
  506.                 break;
  507.             }
  508.             }
  509.             if (doc->media[doc->nummedia].width != 0 &&
  510.             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  511.             else
  512.             free(doc->media[doc->nummedia].name);
  513.         }
  514.         }
  515.         section_len += line_len;
  516.         if (doc->nummedia != 0) doc->default_page_media = doc->media;
  517.     }
  518.     }
  519.  
  520.     if (iscomment(line, "%%EndComments")) {
  521.     readline(line, sizeof line, file, &position, &line_len);
  522.     section_len += line_len;
  523.     }
  524.     doc->endheader = position;
  525.     doc->lenheader = section_len - line_len;
  526.  
  527.     /* Optional Preview comments for encapsulated PostScript files */ 
  528.  
  529.     while (blank(line) &&
  530.        readline(line, sizeof line, file, &position, &line_len)) {
  531.     }
  532.  
  533.     if (doc->epsf && iscomment(line, "%%BeginPreview")) {
  534.     doc->beginpreview = position;
  535.     section_len = line_len;
  536.     while (readline(line, sizeof line, file, &position, &line_len) &&
  537.            !iscomment(line, "%%EndPreview")) {
  538.         section_len += line_len;
  539.     }
  540.     section_len += line_len;
  541.     readline(line, sizeof line, file, &position, &line_len);
  542.     section_len += line_len;
  543.     doc->endpreview = position;
  544.     doc->lenpreview = section_len - line_len;
  545.     }
  546.  
  547.     /* Page Defaults for Version 3.0 files */
  548.  
  549.     while (blank(line) &&
  550.        readline(line, sizeof line, file, &position, &line_len)) {
  551.     }
  552.  
  553.     if (iscomment(line, "%%BeginDefaults")) {
  554.     doc->begindefaults = position;
  555.     section_len = line_len;
  556.     while (readline(line, sizeof line, file, &position, &line_len) &&
  557.            !iscomment(line, "%%EndDefaults")) {
  558.         section_len += line_len;
  559.         if (!iscomment(line, "%%")) {
  560.         /* Do nothing */
  561.         } else if (doc->default_page_orientation == NONE &&
  562.         iscomment(line+2, "PageOrientation:")) {
  563.         sscanf(line+length("%%PageOrientation:"), "%s", text);
  564.         if (strcmp(text, "Portrait") == 0) {
  565.             doc->default_page_orientation = PORTRAIT;
  566.         } else if (strcmp(text, "Landscape") == 0) {
  567.             doc->default_page_orientation = LANDSCAPE;
  568.         }
  569.         } else if (page_media_set == NONE &&
  570.                iscomment(line+2, "PageMedia:")) {
  571.         cp = gettext(line+length("%%PageMedia:"), NULL);
  572.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  573.             if (strcmp(cp, dmp->name) == 0) {
  574.             doc->default_page_media = dmp;
  575.             page_media_set = 1;
  576.             break;
  577.             }
  578.         }
  579.         free(cp);
  580.         } else if (page_bb_set == NONE &&
  581.                iscomment(line+2, "PageBoundingBox:")) {
  582.         if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  583.                &(doc->default_page_boundingbox[LLX]),
  584.                &(doc->default_page_boundingbox[LLY]),
  585.                &(doc->default_page_boundingbox[URX]),
  586.                &(doc->default_page_boundingbox[URY])) == 4)
  587.             page_bb_set = 1;
  588.         else {
  589.             float fllx, flly, furx, fury;
  590.             if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
  591.                    &fllx, &flly, &furx, &fury) == 4) {
  592.             page_bb_set = 1;
  593.             doc->default_page_boundingbox[LLX] = fllx;
  594.             doc->default_page_boundingbox[LLY] = flly;
  595.             doc->default_page_boundingbox[URX] = furx;
  596.             doc->default_page_boundingbox[URY] = fury;
  597.             if (fllx < doc->default_page_boundingbox[LLX])
  598.                 doc->default_page_boundingbox[LLX]--;
  599.             if (flly < doc->default_page_boundingbox[LLY])
  600.                 doc->default_page_boundingbox[LLY]--;
  601.             if (furx > doc->default_page_boundingbox[URX])
  602.                 doc->default_page_boundingbox[URX]++;
  603.             if (fury > doc->default_page_boundingbox[URY])
  604.                 doc->default_page_boundingbox[URY]++;
  605.             }
  606.         }
  607.         }
  608.     }
  609.     section_len += line_len;
  610.     readline(line, sizeof line, file, &position, &line_len);
  611.     section_len += line_len;
  612.     doc->enddefaults = position;
  613.     doc->lendefaults = section_len - line_len;
  614.     }
  615.  
  616.     /* Document Prolog */
  617.  
  618.     while (blank(line) &&
  619.        readline(line, sizeof line, file, &position, &line_len)) {
  620.     }
  621.  
  622.     if (!iscomment(line, "%%BeginSetup") && !iscomment(line, "%%Page:") &&
  623.     !iscomment(line, "%%Trailer") && !iscomment(line, "%%EOF")) {
  624.     doc->beginprolog = position;
  625.     section_len = line_len;
  626.     preread = 1;
  627.  
  628.     while ((preread ||
  629.         readline(line, sizeof line, file, &position, &line_len)) &&
  630.            !iscomment(line, "%%EndProlog") &&
  631.            !iscomment(line, "%%BeginSetup") &&
  632.            !iscomment(line, "%%Page:") && !iscomment(line, "%%Trailer") &&
  633.            !iscomment(line, "%%EOF")) {
  634.         if (!preread) section_len += line_len;
  635.         preread = 0;
  636.     }
  637.     section_len += line_len;
  638.     if (iscomment(line, "%%EndProlog")) {
  639.         readline(line, sizeof line, file, &position, &line_len);
  640.         section_len += line_len;
  641.     }
  642.     doc->endprolog = position;
  643.     doc->lenprolog = section_len - line_len;
  644.     }
  645.  
  646.     /* Document Setup,  Page Defaults found here for Version 2 files */
  647.  
  648.     while (blank(line) &&
  649.        readline(line, sizeof line, file, &position, &line_len)) {
  650.     }
  651.  
  652.     if (!iscomment(line, "%%Page:") && !iscomment(line, "%%Trailer") &&
  653.     !iscomment(line, "%%EOF")) {
  654.     doc->beginsetup = position;
  655.     section_len = line_len;
  656.     preread = 1;
  657.     while ((preread ||
  658.         readline(line, sizeof line, file, &position, &line_len)) &&
  659.            !iscomment(line, "%%EndSetup") && !iscomment(line, "%%Page:") &&
  660.            !iscomment(line, "%%Trailer") && !iscomment(line, "%%EOF")) {
  661.         if (!preread) section_len += line_len;
  662.         preread = 0;
  663.         if (!iscomment(line, "%%")) {
  664.         /* Do nothing */
  665.         } else if (doc->default_page_orientation == NONE &&
  666.         iscomment(line+2, "PageOrientation:")) {
  667.         sscanf(line+length("%%PageOrientation:"), "%s", text);
  668.         if (strcmp(text, "Portrait") == 0) {
  669.             doc->default_page_orientation = PORTRAIT;
  670.         } else if (strcmp(text, "Landscape") == 0) {
  671.             doc->default_page_orientation = LANDSCAPE;
  672.         }
  673.         } else if (page_media_set == NONE &&
  674.                iscomment(line+2, "PaperSize:")) {
  675.         cp = gettext(line+length("%%PaperSize:"), NULL);
  676.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  677.             /* Note: Paper size comment uses down cased paper size
  678.              * name.  Case insensitive compares are only used for
  679.              * PaperSize comments.
  680.              */
  681.             if (strcasecmp(cp, dmp->name) == 0) {
  682.             doc->default_page_media = dmp;
  683.             page_media_set = 1;
  684.             break;
  685.             }
  686.         }
  687.         free(cp);
  688.         } else if (page_bb_set == NONE &&
  689.                iscomment(line+2, "PageBoundingBox:")) {
  690.         if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  691.                &(doc->default_page_boundingbox[LLX]),
  692.                &(doc->default_page_boundingbox[LLY]),
  693.                &(doc->default_page_boundingbox[URX]),
  694.                &(doc->default_page_boundingbox[URY])) == 4)
  695.             page_bb_set = 1;
  696.         else {
  697.             float fllx, flly, furx, fury;
  698.             if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
  699.                    &fllx, &flly, &furx, &fury) == 4) {
  700.             page_bb_set = 1;
  701.             doc->default_page_boundingbox[LLX] = fllx;
  702.             doc->default_page_boundingbox[LLY] = flly;
  703.             doc->default_page_boundingbox[URX] = furx;
  704.             doc->default_page_boundingbox[URY] = fury;
  705.             if (fllx < doc->default_page_boundingbox[LLX])
  706.                 doc->default_page_boundingbox[LLX]--;
  707.             if (flly < doc->default_page_boundingbox[LLY])
  708.                 doc->default_page_boundingbox[LLY]--;
  709.             if (furx > doc->default_page_boundingbox[URX])
  710.                 doc->default_page_boundingbox[URX]++;
  711.             if (fury > doc->default_page_boundingbox[URY])
  712.                 doc->default_page_boundingbox[URY]++;
  713.             }
  714.         }
  715.         }
  716.     }
  717.     section_len += line_len;
  718.     if (iscomment(line, "%%EndSetup")) {
  719.         readline(line, sizeof line, file, &position, &line_len);
  720.         section_len += line_len;
  721.     }
  722.     doc->endsetup = position;
  723.     doc->lensetup = section_len - line_len;
  724.     }
  725.  
  726.     /* Individual Pages */
  727.  
  728.     while (blank(line) &&
  729.        readline(line, sizeof line, file, &position, &line_len)) {
  730.     }
  731.  
  732. newpage:
  733.     while (iscomment(line, "%%Page:")) {
  734.     if (maxpages == 0) {
  735.         maxpages = 1;
  736.         doc->pages = (struct page *) calloc(maxpages, sizeof(struct page));
  737.         if (doc->pages == NULL) {
  738.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  739.         exit(-1);
  740.         }
  741.     }
  742.     label = gettext(line+length("%%Page:"), &next_char);
  743.     if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
  744.     if (nextpage == 1) {
  745.         ignore = thispage != 1;
  746.     }
  747.     if (!ignore && thispage != nextpage) {
  748.         free(label);
  749.         doc->numpages--;
  750.         goto continuepage;
  751.     }
  752.     nextpage++;
  753.     if (doc->numpages == maxpages) {
  754.         maxpages++;
  755.         doc->pages = (struct page *)
  756.              realloc(doc->pages, maxpages*sizeof (struct page));
  757.         if (doc->pages == NULL) {
  758.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  759.         exit(-1);
  760.         }
  761.     }
  762.     memset(&(doc->pages[doc->numpages]), 0, sizeof(struct page));
  763.     page_bb_set = NONE;
  764.     doc->pages[doc->numpages].label = label;
  765.     doc->pages[doc->numpages].begin = position;
  766.     section_len = line_len;
  767. continuepage:
  768.     while (readline(line, sizeof line, file, &position, &line_len) &&
  769.            !iscomment(line, "%%Page:") && !iscomment(line, "%%Trailer") &&
  770.            !iscomment(line, "%%EOF")) {
  771.         section_len += line_len;
  772.         if (!iscomment(line, "%%")) {
  773.         /* Do nothing */
  774.         } else if (doc->pages[doc->numpages].orientation == NONE &&
  775.         iscomment(line+2, "PageOrientation:")) {
  776.         sscanf(line+length("%%PageOrientation:"), "%s", text);
  777.         if (strcmp(text, "Portrait") == 0) {
  778.             doc->pages[doc->numpages].orientation = PORTRAIT;
  779.         } else if (strcmp(text, "Landscape") == 0) {
  780.             doc->pages[doc->numpages].orientation = LANDSCAPE;
  781.         }
  782.         } else if (doc->pages[doc->numpages].media == NULL &&
  783.                iscomment(line+2, "PageMedia:")) {
  784.         cp = gettext(line+length("%%PageMedia:"), NULL);
  785.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  786.             if (strcmp(cp, dmp->name) == 0) {
  787.             doc->pages[doc->numpages].media = dmp;
  788.             break;
  789.             }
  790.         }
  791.         free(cp);
  792.         } else if (doc->pages[doc->numpages].media == NULL &&
  793.                iscomment(line+2, "PaperSize:")) {
  794.         cp = gettext(line+length("%%PaperSize:"), NULL);
  795.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  796.             /* Note: Paper size comment uses down cased paper size
  797.              * name.  Case insensitive compares are only used for
  798.              * PaperSize comments.
  799.              */
  800.             if (strcasecmp(cp, dmp->name) == 0) {
  801.             doc->pages[doc->numpages].media = dmp;
  802.             break;
  803.             }
  804.         }
  805.         free(cp);
  806.         } else if ((page_bb_set == NONE || page_bb_set == ATEND) &&
  807.                iscomment(line+2, "PageBoundingBox:")) {
  808.         sscanf(line+length("%%PageBoundingBox:"), "%s", text);
  809.         if (strcmp(text, "(atend)") == 0) {
  810.             page_bb_set = ATEND;
  811.         } else {
  812.             if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  813.                 &(doc->pages[doc->numpages].boundingbox[LLX]),
  814.                 &(doc->pages[doc->numpages].boundingbox[LLY]),
  815.                 &(doc->pages[doc->numpages].boundingbox[URX]),
  816.                 &(doc->pages[doc->numpages].boundingbox[URY])) == 4)
  817.             if (page_bb_set == NONE) page_bb_set = 1;
  818.             else {
  819.             float fllx, flly, furx, fury;
  820.             if (sscanf(line+length("%%PageBoundingBox:"),
  821.                    "%f %f %f %f",
  822.                    &fllx, &flly, &furx, &fury) == 4) {
  823.                 if (page_bb_set == NONE) page_bb_set = 1;
  824.                 doc->pages[doc->numpages].boundingbox[LLX] = fllx;
  825.                 doc->pages[doc->numpages].boundingbox[LLY] = flly;
  826.                 doc->pages[doc->numpages].boundingbox[URX] = furx;
  827.                 doc->pages[doc->numpages].boundingbox[URY] = fury;
  828.                 if (fllx <
  829.                     doc->pages[doc->numpages].boundingbox[LLX])
  830.                 doc->pages[doc->numpages].boundingbox[LLX]--;
  831.                 if (flly <
  832.                     doc->pages[doc->numpages].boundingbox[LLY])
  833.                 doc->pages[doc->numpages].boundingbox[LLY]--;
  834.                 if (furx >
  835.                     doc->pages[doc->numpages].boundingbox[URX])
  836.                 doc->pages[doc->numpages].boundingbox[URX]++;
  837.                 if (fury >
  838.                     doc->pages[doc->numpages].boundingbox[URY])
  839.                 doc->pages[doc->numpages].boundingbox[URY]++;
  840.             }
  841.             }
  842.         }
  843.         }
  844.     }
  845.     section_len += line_len;
  846.     doc->pages[doc->numpages].end = position;
  847.     doc->pages[doc->numpages].len = section_len - line_len;
  848.     doc->numpages++;
  849.     }
  850.  
  851.     /* Document Trailer */
  852.  
  853.     doc->begintrailer = position;
  854.     section_len = line_len;
  855.  
  856.     preread = 1;
  857.     while ((preread ||
  858.         readline(line, sizeof line, file, &position, &line_len)) &&
  859.        !iscomment(line, "%%EOF")) {
  860.     if (!preread) section_len += line_len;
  861.     preread = 0;
  862.     if (!iscomment(line, "%%")) {
  863.         /* Do nothing */
  864.     } else if (iscomment(line+2, "Page:")) {
  865.         free(gettext(line+length("%%Page:"), &next_char));
  866.         if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
  867.         if (!ignore && thispage == nextpage) {
  868.         if (doc->numpages > 0) {
  869.             doc->pages[doc->numpages-1].end = position;
  870.             doc->pages[doc->numpages-1].len += section_len - line_len;
  871.         }
  872.         goto newpage;
  873.         }
  874.     } else if (bb_set == ATEND && iscomment(line+2, "BoundingBox:")) {
  875.         if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
  876.                &(doc->boundingbox[LLX]),
  877.                &(doc->boundingbox[LLY]),
  878.                &(doc->boundingbox[URX]),
  879.                &(doc->boundingbox[URY])) != 4) {
  880.         float fllx, flly, furx, fury;
  881.         if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
  882.                &fllx, &flly, &furx, &fury) == 4) {
  883.             doc->boundingbox[LLX] = fllx;
  884.             doc->boundingbox[LLY] = flly;
  885.             doc->boundingbox[URX] = furx;
  886.             doc->boundingbox[URY] = fury;
  887.             if (fllx < doc->boundingbox[LLX])
  888.             doc->boundingbox[LLX]--;
  889.             if (flly < doc->boundingbox[LLY])
  890.             doc->boundingbox[LLY]--;
  891.             if (furx > doc->boundingbox[URX])
  892.             doc->boundingbox[URX]++;
  893.             if (fury > doc->boundingbox[URY])
  894.             doc->boundingbox[URY]++;
  895.         }
  896.         }
  897.     } else if (orientation_set == ATEND &&
  898.            iscomment(line+2, "Orientation:")) {
  899.         sscanf(line+length("%%Orientation:"), "%s", text);
  900.         if (strcmp(text, "Portrait") == 0) {
  901.         doc->orientation = PORTRAIT;
  902.         } else if (strcmp(text, "Landscape") == 0) {
  903.         doc->orientation = LANDSCAPE;
  904.         }
  905.     } else if (page_order_set == ATEND && iscomment(line+2, "PageOrder:")) {
  906.         sscanf(line+length("%%PageOrder:"), "%s", text);
  907.         if (strcmp(text, "Ascend") == 0) {
  908.         doc->pageorder = ASCEND;
  909.         } else if (strcmp(text, "Descend") == 0) {
  910.         doc->pageorder = DESCEND;
  911.         } else if (strcmp(text, "Special") == 0) {
  912.         doc->pageorder = SPECIAL;
  913.         }
  914.     } else if (pages_set == ATEND && iscomment(line+2, "Pages:")) {
  915.         if (sscanf(line+length("%%Pages:"), "%*u %d", &i) == 1) {
  916.         if (page_order_set == NONE) {
  917.             if (i == -1) doc->pageorder = DESCEND;
  918.             else if (i == 0) doc->pageorder = SPECIAL;
  919.             else if (i == 1) doc->pageorder = ASCEND;
  920.         }
  921.         }
  922.     }
  923.     }
  924.     section_len += line_len;
  925.     if (iscomment(line, "%%EOF")) {
  926.     readline(line, sizeof line, file, &position, &line_len);
  927.     section_len += line_len;
  928.     }
  929.     doc->endtrailer = position;
  930.     doc->lentrailer = section_len - line_len;
  931.  
  932.     section_len = line_len;
  933.     preread = 1;
  934.     while (preread ||
  935.        readline(line, sizeof line, file, &position, &line_len)) {
  936.     if (!preread) section_len += line_len;
  937.     preread = 0;
  938.     if (iscomment(line, "%%Page:")) {
  939.         free(gettext(line+length("%%Page:"), &next_char));
  940.         if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
  941.         if (!ignore && thispage == nextpage) {
  942.         doc->pages[doc->numpages-1].end = position;
  943.         doc->pages[doc->numpages-1].len += doc->lentrailer +
  944.                            section_len - line_len;
  945.         goto newpage;
  946.         }
  947.     }
  948.     }
  949.     return doc;
  950. }
  951.  
  952. /*
  953.  *    psfree -- free dynamic storage associated with document structure.
  954.  */
  955.  
  956. void
  957. psfree(doc)
  958.     struct document *doc;
  959. {
  960.     int i;
  961.  
  962.     if (doc) {
  963.     for (i=0; i<doc->numpages; i++) {
  964.         if (doc->pages[i].label) free(doc->pages[i].label);
  965.     }
  966.     for (i=0; i<doc->nummedia; i++) {
  967.         if (doc->media[i].name) free(doc->media[i].name);
  968.     }
  969.     if (doc->title) free(doc->title);
  970.     if (doc->date) free(doc->date);
  971.     if (doc->pages) free(doc->pages);
  972.     if (doc->media) free(doc->media);
  973.     free(doc);
  974.     }
  975. }
  976.  
  977. /*
  978.  * gettextine -- skip over white space and return the rest of the line.
  979.  *               If the text begins with '(' return the text string
  980.  *         using gettext().
  981.  */
  982.  
  983. static char *
  984. gettextline(line)
  985.     char *line;
  986. {
  987.     char *cp;
  988.  
  989.     while (*line && (*line == ' ' || *line == '\t')) line++;
  990.     if (*line == '(') {
  991.     return gettext(line, NULL);
  992.     } else {
  993.     if (strlen(line) == 0) return NULL;
  994.     cp = (char *) malloc(strlen(line));
  995.     if (cp == NULL) {
  996.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  997.         exit(-1);
  998.     }
  999.     strncpy(cp, line, strlen(line)-1);
  1000.     cp[strlen(line)-1] = '\0';
  1001.     return cp;
  1002.     }
  1003. }
  1004.  
  1005. /*
  1006.  *    gettext -- return the next text string on the line.
  1007.  *           return NULL if nothing is present.
  1008.  */
  1009.  
  1010. static char *
  1011. gettext(line, next_char)
  1012.     char *line;
  1013.     char **next_char;
  1014. {
  1015.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1016.     char *cp;
  1017.     int quoted=0;
  1018.  
  1019.     while (*line && (*line == ' ' || *line == '\t')) line++;
  1020.     cp = text;
  1021.     if (*line == '(') {
  1022.     int level = 0;
  1023.     quoted=1;
  1024.     line++;
  1025.     while (*line && !(*line == ')' && level == 0 )) {
  1026.         if (*line == '\\') {
  1027.         if (*(line+1) == 'n') {
  1028.             *cp++ = '\n';
  1029.             line += 2;
  1030.         } else if (*(line+1) == 'r') {
  1031.             *cp++ = '\r';
  1032.             line += 2;
  1033.         } else if (*(line+1) == 't') {
  1034.             *cp++ = '\t';
  1035.             line += 2;
  1036.         } else if (*(line+1) == 'b') {
  1037.             *cp++ = '\b';
  1038.             line += 2;
  1039.         } else if (*(line+1) == 'f') {
  1040.             *cp++ = '\f';
  1041.             line += 2;
  1042.         } else if (*(line+1) == '\\') {
  1043.             *cp++ = '\\';
  1044.             line += 2;
  1045.         } else if (*(line+1) == '(') {
  1046.             *cp++ = '(';
  1047.             line += 2;
  1048.         } else if (*(line+1) == ')') {
  1049.             *cp++ = ')';
  1050.             line += 2;
  1051.         } else if (*(line+1) >= '0' && *(line+1) <= '9') {
  1052.             if (*(line+2) >= '0' && *(line+2) <= '9') {
  1053.             if (*(line+3) >= '0' && *(line+3) <= '9') {
  1054.                 *cp++ = ((*(line+1) - '0')*8 + *(line+2) - '0')*8 +
  1055.                     *(line+3) - '0';
  1056.                 line += 4;
  1057.             } else {
  1058.                 *cp++ = (*(line+1) - '0')*8 + *(line+2) - '0';
  1059.                 line += 3;
  1060.             }
  1061.             } else {
  1062.             *cp++ = *(line+1) - '0';
  1063.             line += 2;
  1064.             }
  1065.         } else {
  1066.             line++;
  1067.             *cp++ = *line++;
  1068.         }
  1069.         } else if (*line == '(') {
  1070.         level++;
  1071.         *cp++ = *line++;
  1072.         } else if (*line == ')') {
  1073.         level--;
  1074.         *cp++ = *line++;
  1075.         } else {
  1076.         *cp++ = *line++;
  1077.         }
  1078.     }
  1079.     } else {
  1080.     while (*line && !(*line == ' ' || *line == '\t' || *line == '\n'))
  1081.         *cp++ = *line++;
  1082.     }
  1083.     *cp = '\0';
  1084.     if (next_char) *next_char = line;
  1085.     if (!quoted && strlen(text) == 0) return NULL;
  1086.     cp = (char *) malloc(strlen(text)+1);
  1087.     if (cp == NULL) {
  1088.     pserror("Fatal Error: Dynamic memory exhausted.\n");
  1089.     exit(-1);
  1090.     }
  1091.     strcpy(cp, text);
  1092.     return cp;
  1093. }
  1094.  
  1095. /*
  1096.  *    readline -- Read the next line in the postscript file.
  1097.  *                  Automatically skip over data (as indicated by
  1098.  *                  %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
  1099.  *            comments.)
  1100.  *            Also, skip over included documents (as indicated by
  1101.  *            %%BeginDocument/%%EndDocument comments.)
  1102.  */
  1103.  
  1104. static char *
  1105. readline(line, size, fp, position, line_len)
  1106.     char *line;
  1107.     int size;
  1108.     FILE *fp;
  1109.     long *position;
  1110.     unsigned int *line_len;
  1111. {
  1112.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1113.     char save[PSLINELENGTH];    /* Temporary storage for text */
  1114.     char *cp;
  1115.     unsigned int num;
  1116.     unsigned int nbytes;
  1117.     int i;
  1118.     char buf[BUFSIZ];
  1119.  
  1120.     if (position) *position = ftell(fp);
  1121.     cp = fgets(line, size, fp);
  1122.     if (cp == NULL) line[0] = '\0';
  1123.     *line_len = strlen(line);
  1124. #ifdef __TURBOC__
  1125.     /* remove MS-DOS carriage-return */
  1126.     if ((i = *line_len) >= 2) {
  1127.     if ((line[i-2] == '\r') && (line[i-1] == '\n')) {
  1128.         line[i-2] = '\n';
  1129.         line[i-1] = '\0';
  1130.     }
  1131.     }
  1132. #endif
  1133.     if (iscomment(line, "%%BeginDocument:")) {
  1134.     strcpy(save, line+7);
  1135.     while (readline(line, size, fp, NULL, &nbytes) &&
  1136.            !iscomment(line, "%%EndDocument")) {
  1137.         *line_len += nbytes;
  1138.     }
  1139.     *line_len += nbytes;
  1140.     strcpy(line, save);
  1141.     } else if (iscomment(line, "%%BeginFeature:")) {
  1142.     strcpy(save, line+7);
  1143.     while (readline(line, size, fp, NULL, &nbytes) &&
  1144.            !iscomment(line, "%%EndFeature")) {
  1145.         *line_len += nbytes;
  1146.     }
  1147.     *line_len += nbytes;
  1148.     strcpy(line, save);
  1149.     } else if (iscomment(line, "%%BeginFile:")) {
  1150.     strcpy(save, line+7);
  1151.     while (readline(line, size, fp, NULL, &nbytes) &&
  1152.            !iscomment(line, "%%EndFile")) {
  1153.         *line_len += nbytes;
  1154.     }
  1155.     *line_len += nbytes;
  1156.     strcpy(line, save);
  1157.     } else if (iscomment(line, "%%BeginFont:")) {
  1158.     strcpy(save, line+7);
  1159.     while (readline(line, size, fp, NULL, &nbytes) &&
  1160.            !iscomment(line, "%%EndFont")) {
  1161.         *line_len += nbytes;
  1162.     }
  1163.     *line_len += nbytes;
  1164.     strcpy(line, save);
  1165.     } else if (iscomment(line, "%%BeginProcSet:")) {
  1166.     strcpy(save, line+7);
  1167.     while (readline(line, size, fp, NULL, &nbytes) &&
  1168.            !iscomment(line, "%%EndProcSet")) {
  1169.         *line_len += nbytes;
  1170.     }
  1171.     *line_len += nbytes;
  1172.     strcpy(line, save);
  1173.     } else if (iscomment(line, "%%BeginResource:")) {
  1174.     strcpy(save, line+7);
  1175.     while (readline(line, size, fp, NULL, &nbytes) &&
  1176.            !iscomment(line, "%%EndResource")) {
  1177.         *line_len += nbytes;
  1178.     }
  1179.     *line_len += nbytes;
  1180.     strcpy(line, save);
  1181.     } else if (iscomment(line, "%%BeginData:")) {
  1182.     text[0] = '\0';
  1183.     strcpy(save, line+7);
  1184.     if (sscanf(line+length("%%BeginData:"), "%d %*s %s", &num, text) >= 1) {
  1185.         if (strcmp(text, "Lines") == 0) {
  1186.         for (i=0; i < num; i++) {
  1187.             cp = fgets(line, size, fp);
  1188.             *line_len += cp ? strlen(line) : 0;
  1189.         }
  1190.         } else {
  1191.         while (num > BUFSIZ) {
  1192.             fread(buf, sizeof (char), BUFSIZ, fp);
  1193.             *line_len += BUFSIZ;
  1194.             num -= BUFSIZ;
  1195.         }
  1196.         fread(buf, sizeof (char), num, fp);
  1197.         *line_len += num;
  1198.         }
  1199.     }
  1200.     while (readline(line, size, fp, NULL, &nbytes) &&
  1201.            !iscomment(line, "%%EndData")) {
  1202.         *line_len += nbytes;
  1203.     }
  1204.     *line_len += nbytes;
  1205.     strcpy(line, save);
  1206.     } else if (iscomment(line, "%%BeginBinary:")) {
  1207.     strcpy(save, line+7);
  1208.     if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
  1209.         while (num > BUFSIZ) {
  1210.         fread(buf, sizeof (char), BUFSIZ, fp);
  1211.         *line_len += BUFSIZ;
  1212.         num -= BUFSIZ;
  1213.         }
  1214.         fread(buf, sizeof (char), num, fp);
  1215.         *line_len += num;
  1216.     }
  1217.     while (readline(line, size, fp, NULL, &nbytes) &&
  1218.            !iscomment(line, "%%EndBinary")) {
  1219.         *line_len += nbytes;
  1220.     }
  1221.     *line_len += nbytes;
  1222.     strcpy(line, save);
  1223.     }
  1224.     return cp;
  1225. }
  1226.  
  1227. /*
  1228.  *    pscopy -- copy lines of Postscript from a section of one file
  1229.  *          to another file.
  1230.  *                Automatically switch to binary copying whenever
  1231.  *                %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
  1232.  *          comments are encountered.
  1233.  */
  1234.  
  1235. void
  1236. pscopy(from, to, begin, end)
  1237.     FILE *from;
  1238.     FILE *to;
  1239.     long begin;            /* set negative to avoid initial seek */
  1240.     long end;
  1241. {
  1242.     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
  1243.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1244.     unsigned int num;
  1245.     int i;
  1246.     char buf[BUFSIZ];
  1247.  
  1248.     if (begin >= 0) fseek(from, begin, SEEK_SET);
  1249.     while (ftell(from) < end) {
  1250.  
  1251.     fgets(line, sizeof line, from);
  1252.     fputs(line, to);
  1253.  
  1254.     if (iscomment(line, "%%BeginData:")) {
  1255.         text[0] = '\0';
  1256.         if (sscanf(line+length("%%BeginData:"),
  1257.                "%d %*s %s", &num, text) >= 1) {
  1258.         if (strcmp(text, "Lines") == 0) {
  1259.             for (i=0; i < num; i++) {
  1260.             fgets(line, sizeof line, from);
  1261.             fputs(line, to);
  1262.             }
  1263.         } else {
  1264.             while (num > BUFSIZ) {
  1265.             fread(buf, sizeof (char), BUFSIZ, from);
  1266.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1267.             num -= BUFSIZ;
  1268.             }
  1269.             fread(buf, sizeof (char), num, from);
  1270.             fwrite(buf, sizeof (char), num, to);
  1271.         }
  1272.         }
  1273.     } else if (iscomment(line, "%%BeginBinary:")) {
  1274.         if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
  1275.         while (num > BUFSIZ) {
  1276.             fread(buf, sizeof (char), BUFSIZ, from);
  1277.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1278.             num -= BUFSIZ;
  1279.         }
  1280.         fread(buf, sizeof (char), num, from);
  1281.         fwrite(buf, sizeof (char), num, to);
  1282.         }
  1283.     }
  1284.     }
  1285. }
  1286.  
  1287. /*
  1288.  *    pscopyuntil -- copy lines of Postscript from a section of one file
  1289.  *               to another file until a particular comment is reached.
  1290.  *                     Automatically switch to binary copying whenever
  1291.  *                     %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
  1292.  *               comments are encountered.
  1293.  */
  1294.  
  1295. char *
  1296. pscopyuntil(from, to, begin, end, comment)
  1297.     FILE *from;
  1298.     FILE *to;
  1299.     long begin;            /* set negative to avoid initial seek */
  1300.     long end;
  1301. #if NeedFunctionPrototypes
  1302.     const
  1303. #endif
  1304.     char *comment;
  1305. {
  1306.     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
  1307.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1308.     unsigned int num;
  1309.     int comment_length;
  1310.     int i;
  1311.     char buf[BUFSIZ];
  1312.     char *cp;
  1313.  
  1314.     comment_length = strlen(comment);
  1315.     if (begin >= 0) fseek(from, begin, SEEK_SET);
  1316.     while (ftell(from) < end) {
  1317.  
  1318.     fgets(line, sizeof line, from);
  1319.  
  1320.     /* iscomment cannot be used here,
  1321.      * because comment_length is not known at compile time. */
  1322.     if (strncmp(line, comment, comment_length) == 0) {
  1323.         cp = (char *) malloc(strlen(line)+1);
  1324.         if (cp == NULL) {
  1325.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  1326.         exit(-1);
  1327.         }
  1328.         strcpy(cp, line);
  1329.         return cp;
  1330.     }
  1331.     fputs(line, to);
  1332.     if (iscomment(line, "%%BeginData:")) {
  1333.         text[0] = '\0';
  1334.         if (sscanf(line+length("%%BeginData:"),
  1335.                "%d %*s %s", &num, text) >= 1) {
  1336.         if (strcmp(text, "Lines") == 0) {
  1337.             for (i=0; i < num; i++) {
  1338.             fgets(line, sizeof line, from);
  1339.             fputs(line, to);
  1340.             }
  1341.         } else {
  1342.             while (num > BUFSIZ) {
  1343.             fread(buf, sizeof (char), BUFSIZ, from);
  1344.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1345.             num -= BUFSIZ;
  1346.             }
  1347.             fread(buf, sizeof (char), num, from);
  1348.             fwrite(buf, sizeof (char), num, to);
  1349.         }
  1350.         }
  1351.     } else if (iscomment(line, "%%BeginBinary:")) {
  1352.         if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
  1353.         while (num > BUFSIZ) {
  1354.             fread(buf, sizeof (char), BUFSIZ, from);
  1355.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1356.             num -= BUFSIZ;
  1357.         }
  1358.         fread(buf, sizeof (char), num, from);
  1359.         fwrite(buf, sizeof (char), num, to);
  1360.         }
  1361.     }
  1362.     }
  1363.     return NULL;
  1364. }
  1365.  
  1366. /*
  1367.  *    blank -- determine whether the line contains nothing but whitespace.
  1368.  */
  1369.  
  1370. static int
  1371. blank(line)
  1372.     char *line;
  1373. {
  1374.     char *cp = line;
  1375.  
  1376.     while (*cp == ' ' || *cp == '\t') cp++;
  1377.     return *cp == '\n' || (*cp == '%' && (line[0] != '%' || line[1] != '%'));
  1378. }
  1379.